/*******************************************************************************************************************
 * The MIT License (MIT)
 *
 * Copyright (c) 2014 Nicolas DAURES
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *******************************************************************************************************************/


/****************************************************************
 * Constants
 ****************************************************************/

var FPS = 60;
var FPS_MARGIN = [100, 10];

var CANVAS_SIZE = [640, 480];
var CANVAS_HALFSIZE = [320, 240];


/****************************************************************
 * Test entities
 ****************************************************************/

// Ball
function Ball()
{
    this.m_Body =       null;
    this.m_Texture =    null;
};

Ball.prototype.initialize = function(a_v2Pos)
{
    var fixtureDef = new b2FixtureDef();
    fixtureDef.shape = new b2CircleShape(20);
    fixtureDef.density = 1.0;
    fixtureDef.restitution = 0.8;
    fixtureDef.friction = 0.2;
    var bodyDef = new b2BodyDef();
    bodyDef.position.x = a_v2Pos.x;
    bodyDef.position.y = a_v2Pos.y;
    bodyDef.type = b2Body.b2_dynamicBody;
    this.m_Body = PhysicEngine.getInstance().getWorld().CreateBody(bodyDef);
    this.m_Body.CreateFixture(fixtureDef);

    this.m_Texture = new Texture();
    RenderEngine.getInstance().addRenderable(this.m_Texture);
    SceneEngine.getInstance().getRootSceneNode().attachSceneNode(this.m_Texture.m_SceneNode);
    this.m_Texture.m_SceneNode.m_v2Scale.x = 40;
    this.m_Texture.m_SceneNode.m_v2Scale.y = 40;
}

Ball.prototype.update = function(a_fdt)
{
    this.m_Texture.m_SceneNode.m_v2Pos.x = this.m_Body.GetPosition().x;
    this.m_Texture.m_SceneNode.m_v2Pos.y = this.m_Body.GetPosition().y;
    this.m_Texture.m_SceneNode.m_fOrientation = 2*Math.PI - this.m_Body.GetAngle();
}

// Ground
function Ground()
{
    this.m_Body =       null;
    this.m_v2HalfSize = null;
    this.m_SceneNode =  null;
};

Ground.prototype.initialize = function(a_v2Pos, a_v2Size)
{
    this.m_v2HalfSize = new b2Vec2();
    this.m_v2HalfSize.x = a_v2Size.x;
    this.m_v2HalfSize.y = a_v2Size.y;

    var fixtureDef = new b2FixtureDef();
    fixtureDef.shape = new b2PolygonShape();
    fixtureDef.shape.SetAsBox(this.m_v2HalfSize.x, this.m_v2HalfSize.y);
    fixtureDef.density = 1.0;
    fixtureDef.restitution = 0.5;
    fixtureDef.friction = 0.2;
    var bodyDef = new b2BodyDef();
    bodyDef.position.x = a_v2Pos.x;
    bodyDef.position.y = a_v2Pos.y;
    bodyDef.type = b2Body.b2_staticBody;
    this.m_Body = PhysicEngine.getInstance().getWorld().CreateBody(bodyDef);
    this.m_Body.CreateFixture(fixtureDef);

    this.m_SceneNode = new SceneNode();
    SceneEngine.getInstance().getRootSceneNode().attachSceneNode(this.m_SceneNode);
}

Ground.prototype.update = function(a_fdt)
{
    this.m_SceneNode.m_v2Pos.x = this.m_Body.GetPosition().x;
    this.m_SceneNode.m_v2Pos.y = this.m_Body.GetPosition().y;
}


/****************************************************************
 * Game launcher
 ****************************************************************/

window.addEventListener('load',
			function ()
			{
			    // Get the canvas
			    var elem = document.getElementById('canvas');
			    if (!elem || !elem.getContext)
			    {
					return;
			    }
			    
			    // Get the 2D context
			    context = elem.getContext('2d');
			    if (!context)
			    {
					return;
			    }

                // Mouse event listener
                window.document.onmousedown = onMouseDown;
                window.document.onmouseup = onMouseUp;
                window.document.onmousemove = onMouseMove;

                // Initialize the test
			    initializeTest();
			    
			    // Game loop
			    iGameLoopId = setInterval(updateTest, 1000/FPS);
			},
			false);

var image = null;
var balls = new Array();
var grounds = new Array();
var timer = 0;
var textMousePos = null;
var textBallPos = null;

function initializeTest()
{
    // Initialize engines
    SceneEngine.getInstance();
	TimeEngine.getInstance();
	RenderEngine.getInstance();
	CameraEngine.getInstance();
	PhysicEngine.getInstance();
    InputEngine.getInstance();

    // Debug infos
	TimeEngine.getInstance().displayFPS(new b2Vec2(240, -230));

    var textPos = new b2Vec2(-30, -230);
    textMousePos = new Text2D();
    textMousePos.setColor("#ff0000");
    textMousePos.setFont("18px arial");
    textMousePos.setText("0, 0");
    textMousePos.getSceneNode().setPosition(textPos);
    SceneEngine.getInstance().getRootSceneNode().attachSceneNode(textMousePos.getSceneNode());
    RenderEngine.getInstance().addRenderable(textMousePos);

    textPos = new b2Vec2(-230, -230);
    textBallPos = new Text2D();
    textBallPos.setColor("#ff0000");
    textBallPos.setFont("18px arial");
    textBallPos.setText("0, 0");
    textBallPos.getSceneNode().setPosition(textPos);
    SceneEngine.getInstance().getRootSceneNode().attachSceneNode(textBallPos.getSceneNode());
    RenderEngine.getInstance().addRenderable(textBallPos);

    // Ball texture
    image = new Image();
    image.src = "test_physic.png";

    grounds[0] = new Ground();
    grounds[0].initialize(new b2Vec2(0, -200), new b2Vec2(250, 20));

    grounds[1] = new Ground();
    grounds[1].initialize(new b2Vec2(-230, 0), new b2Vec2(20, 200));

    grounds[2] = new Ground();
    grounds[2].initialize(new b2Vec2(230, 0), new b2Vec2(20, 200));
}

function updateTest()
{
    // Create random balls
    if (balls.length < 50)
    {
        timer += TimeEngine.getInstance().getDeltaTime();
        if (timer > 0.5)
        {
            var ball = new Ball();
            ball.initialize(new b2Vec2(0, 200));
            ball.m_Texture.m_Image = image;
            ball.m_Body.SetLinearVelocity(new b2Vec2(randomf(-300, 300), 0));
            balls.push(ball);

            timer = 0;
        }
    }

    // Add mouse force
    if (Mouse.getInstance().m_aButtons[0] == InputState.PRESSED)
    {
        for (var i = 0; i < balls.length; i++)
        {
            var v2CamPos = CameraEngine.getInstance().m_SceneNode.m_v2Pos;
            var v2BallPosInScreen = convertScenePosToScreenPos(balls[i].m_Body.GetPosition(), v2CamPos);
            var v2Dir = new b2Vec2(v2BallPosInScreen.x - Mouse.getInstance().m_v2Pos.x,
                                   v2BallPosInScreen.y + Mouse.getInstance().m_v2Pos.y);
            if (Math.abs(v2Dir.x) > 50)
            {
                v2Dir.x = v2Dir.x > 0 ? 50 : -50;
            }
            if (Math.abs(v2Dir.y) > 50)
            {
                v2Dir.y = v2Dir.y > 0 ? 50 : -50;
            }
            else
            {
                var test=true;
            }
            v2Dir.x = v2Dir.x > 0 ? 50 - v2Dir.x : -50 + v2Dir.x;
            v2Dir.y = v2Dir.y > 0 ? 50 - v2Dir.y : -50 + v2Dir.y;
            v2Dir.x = v2Dir.x * 6000;
            v2Dir.y = v2Dir.y * 6000;
            if (v2Dir.x != 0 || v2Dir.y != 0)
            {
                balls[i].m_Body.ApplyImpulse(v2Dir, balls[i].m_Body.GetPosition());
            }
        }
    }

    // Update engines
    TimeEngine.getInstance().update();
	PhysicEngine.getInstance().update();

	// Update gameplay
    for (var i = 0; i < balls.length; i++)
    {
    	balls[i].update(TimeEngine.getInstance().m_fDeltaTime);
    }
    for (var i = 0; i < grounds.length; i++)
    {
        grounds[i].update(TimeEngine.getInstance().m_fDeltaTime);
    }

	// Update engines
	SceneEngine.getInstance().update();
	CameraEngine.getInstance().update();
	RenderEngine.getInstance().update();
    InputEngine.getInstance().update();

    for (var i = 0; i < grounds.length; i++)
    {
        var v2GroundPos = convertScenePosToScreenPos(grounds[i].m_SceneNode.m_v2Pos, new b2Vec2(0, 0));
        var v2HalfSize = grounds[i].m_v2HalfSize;
        context.save();
        context.fillStyle = 'black';
        context.fillRect(v2GroundPos.x - v2HalfSize.x, v2GroundPos.y - v2HalfSize.y, v2HalfSize.x * 2, v2HalfSize.y * 2);
        context.restore();
    }

    // Mouse position
    if (balls.length > 0)
    {
        var v2BallPos = convertScenePosToScreenPos(balls[0].m_Body.GetPosition(), v2CamPos);
        textMousePos.setText("Mouse Pos : " + Math.floor(Mouse.getInstance().m_v2Pos.x) + ", " + Math.floor(Mouse.getInstance().m_v2Pos.y));
        textBallPos.setText("Ball Pos : " + Math.floor(v2BallPos.x) + ", " + Math.floor(v2BallPos.y));
    }
}
